package exp5;


import java.util.Stack;

public class MyBC {


	public double GetResult(String infix) throws Exception {	
		StringBuffer suffix = new StringBuffer();
		InfixToSuffix(infix, suffix);
		return CalcSuffix(suffix.toString());
	}

	public String ExpressionOut(String infix) throws Exception{
		StringBuffer suffix = new StringBuffer();
		InfixToSuffix(infix, suffix);
		return suffix.toString();
		
	}
	private void InfixToSuffix(String infix, StringBuffer suffix) throws Exception {
		Stack<Character> s = new Stack<>();
		int iLen = infix.length();           
		double num = 0;
		for (int i = 0;i < iLen;i++) {

			if (infix.charAt(i) == ' ')
				continue;
			else if (IsDigit(infix.charAt(i)))
				suffix.append(infix.charAt(i));
			else if (infix.charAt(i) == '(')
				s.push(infix.charAt(i));

			else if (infix.charAt(i) == ')') {
				while (s.peek() != '(') {
					suffix.append(s.peek());
					s.pop();
				}		
				s.pop();
			}
			else if (infix.charAt(i) == '+' || infix.charAt(i) == '-') {
				suffix.append(' ');
				if (s.empty() || s.peek() == '(')
					s.push(infix.charAt(i));
				else {
					do {
						suffix.append(s.peek());
						s.pop();
					} while (!s.empty() && s.peek() != '(');
					s.push(infix.charAt(i));
				}
			}
			else if (infix.charAt(i) == '*' || infix.charAt(i) == '/'){
				suffix.append(' ');
				if (GetPriority(s.peek(), infix.charAt(i)) == 1)
					s.push(infix.charAt(i));
				else {   
					while (!s.empty() && (GetPriority(s.peek(), infix.charAt(i)) < 1) && s.peek() != '(') {
						suffix.append(s.peek());
						s.pop();
					}
					s.push(infix.charAt(i));
			}
		}
	}

		while (!s.empty()) {
			suffix.append(s.peek());
			s.pop();
		}
	}
	

	private double CalcSuffix(String suffix) {				
		Stack<Double> s = new Stack<>();  
		int iLen = suffix.length();			 
		double result = 0;                  
		StringBuffer temp = new StringBuffer();					
		for (int i = 0;i < iLen;i++) {
			if (IsDigit(suffix.charAt(i)))
				temp.append(suffix.charAt(i));
			else if (suffix.charAt(i) == ' ') { 
				if (temp.length() > 0) {
					s.push(Double.valueOf(temp.toString()));
					temp.setLength(0);
				}
			}

			else if (IsOperator(suffix.charAt(i))) {

				if (temp.length() > 0){
					s.push(Double.valueOf(temp.toString()));
					temp.setLength(0);
				}
				double op1 = s.peek();
				s.pop();
				double op2 = s.peek();
				s.pop();
				result = Calc(op1, op2, suffix.charAt(i));
				s.push( result);
			}
		}
		return s.peek();
	}

	private boolean IsDigit(char ch) {									  
		return (ch >= '0' && ch <= '9') || ch == '.' ? true : false;
	}

	private boolean IsOperator(char ch) {									
		return ch == '+' || ch == '-' || ch == '*' || ch == '/' ? true : false;
	}
								
	private int GetPriority(char op1, char op2) throws Exception {
		if ((op1 == '+' || op1 == '-') && (op2 == '-' || op2 == '+'))
			return 0;
		else if (op1 == op2)
			return 0;
		else if ((op1 == '+' || op1 == '-') && (op2 == '*' || op2 == '/'))
			return 1;
		else if ((op1 == '*' || op1 == '/') && (op2 == '-' || op2 == '+'))
			return -1;
		else if ((op1 == '*' || op1 == '/') && (op2 == '*' || op2 == '/') && op1 != op2)
			return 0;
		else 
			throw new Exception("Error");
	}
	

	private double Calc(double op1, double op2, char op) {			
		switch (op) {
		case '+': return op2 + op1;
		case '-': return op2 - op1;
		case '*': return op2 * op1;
		case '/': if (op1 != 0) return op2 / op1;
				  else return 0;
		default:  return 0;
		}
	}

}
